import os
import wx
import wx.lib.dragscroller

from LMG.GUI.lists import FileInfoList, PeersList, GeneralInfoList
from LMG.GUI.Base.ArtManager import ArtManager
from LMG.GUI.Base.widgets import TitlePanel, Graph, GraphRecord
from LMG.GUI.Base.dhmtimectrl import DHMTimeCtrl
from LMG.Utility.helpers import getIcon
from LMG.Utility.constants import *

class BasePanel(wx.ScrolledWindow):
    """
    Base class for detail panels
    """
    def __init__(self, parent, title, style = wx.HSCROLL|wx.VSCROLL):
        """
        BasePanel initialization
        """
        wx.ScrolledWindow.__init__(self, parent.book, -1, style = style)

        self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))

        self.parent = parent
        self.title = title        
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.scroller = wx.lib.dragscroller.DragScroller(self, 100)

        self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
        self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
        if wx.Platform == "__WXGTK__":
            self.Bind(wx.EVT_SCROLLWIN_THUMBRELEASE, self.OnScrolledChange)
        self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChange)

    def OnSysColourChange(self, event):
        self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))        
        event.Skip()
        
    def OnScrolledChange(self, event):
        self.Refresh()
        event.Skip()
        
    def OnMiddleDown(self, event):
        if self.scroller.timer is None:
            self.scroller.Start(event.GetPosition())
        else:
            self.scroller.Stop()
            
    def initTasks(self):
        """
        Things to do after the subclass has finished its init stage
        """
        self.loadValues()
        self.SetSizer(self.sizer)

    def loadValues(self):
        """
        Dummy function that class members should override
        """ 
        pass
    
class DetailPanel(wx.Panel):
    """
    The main Details panel
    """
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)

        self.torrents = []
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        self.book = wx.Notebook(self, -1)
        if wx.Platform == "__WXMAC__":
            self.book.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
        self.Initialise()

        sizer.Add(self.book, 1, wx.EXPAND, 0)

        self.dockbtn = utility.makeBitmapButton(self,
                                                wx.ArtProvider.GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR, (16,10)),
                                                _('Dock Frame'),
                                                self._OnDock,
                                                btnstyle = wx.NO_BORDER)
        sizer.Add(self.dockbtn, 0, wx.ALIGN_RIGHT|wx.RIGHT, 5*int(wx.Platform=="__WXMAC__"))
        self.dockbtn.Hide()

        self.SetAutoLayout(True)
        self.SetSizerAndFit(sizer)

    def _OnDock(self, event):
        utility.actions[ACTION_TORRENTDETAILS].changeParent()

    def EnableDockButton(self, enable):
        self.dockbtn.Show(enable)
        
    def Initialise(self):
        """
        Initialzes the details pages.
        """
        self.book.DeleteAllPages()
        
        self.generalPage = GeneralPanel(self, _("General"))
        self.networkPage = NetworkPanel(self, _("Network"))
        self.filesPage = FilesPanel(self, _("Files"))
        self.peersPage = PeersPanel(self, _("Peers"))
        self.settingPage = LocalSetting(self, _("Settings"))
        self.graphPage = GraphPanel(self, _("Graph"))
        
        if wx.Platform == "__WXMAC__":
            indexes = [-1]*6
        else:
            self.il = wx.ImageList(16, 16)
            self.il.Add(utility.makeBitmap('misc', 'general.png'))
            self.il.Add(utility.makeBitmap('misc', 'network.png'))
            self.il.Add(utility.makeBitmap('misc', 'files.png'))
            self.il.Add(utility.makeBitmap('misc', 'peers.png'))
            self.il.Add(utility.makeBitmap('misc', 'settings.png'))
            self.il.Add(utility.makeBitmap('misc', 'graph.png'))
            self.book.SetImageList(self.il)
            indexes = range(0, 6)
            
        self.book.AddPage(self.generalPage, _("General"), True, indexes[0])
        self.book.AddPage(self.networkPage, _("Network"), False, indexes[1])
        self.book.AddPage(self.filesPage, _("Files"), False, indexes[2])
        self.book.AddPage(self.peersPage, _("Peers"), False, indexes[3])
        self.book.AddPage(self.settingPage, _("Settings"), False, indexes[4])
        self.book.AddPage(self.graphPage, _("Graph"), False, indexes[5])
            
    def getTorrents(self):
        return self.torrents

    def getTorrent(self):
        if self.torrents:
            return self.torrents[0]
        return None
    
    def removeTorrent(self, torrent):
        # Not even here
        if not torrent or torrent not in self.torrents:
            return

        # Was it the active torrent?
        wasActive = torrent == self.getTorrent()

        # Remove from list
        self.torrents.remove(torrent)

        # Update spew flag
        if wasActive:
            if torrent.status.isActive(checking = False):
                torrent.connection.engine.dow.spewflag.clear()
            if self.torrents:
                torrent =  self.torrents[0]
                if torrent.status.isActive(checking = False):
                    torrent.connection.engine.dow.spewflag.set()
            # Update Details
            self.updateAll()      
        else:
            self.settingPage.torrentsChanged()
#            self.updateSettings()
            
    def addTorrent(self, torrent):
        # Already in list
        if not torrent or torrent in self.torrents:
            return
        # Add to list
        self.torrents.append(torrent)
        # The active torrent
        if len(self.torrents) == 1:
            # Update spew flag
            if torrent.status.isActive(checking = False):
                torrent.connection.engine.dow.spewflag.set()
            # Update Details
            self.updateAll()
        else:
            self.settingPage.torrentsChanged()
#            self.updateSettings()
            
    def updateAll(self):
        torrent = self.getTorrent()
        # Update title
        if torrent:
            utility.window.detailsFrame.SetTitle(torrent.getTitle())
        else:
            utility.window.detailsFrame.SetTitle(_('Torrent Inspector'))
        # Update Details
        self.updateGeneral()
        self.updatePeers()
        self.updateFiles()
        self.updateSettings()
        self.updateNetwork('transfer')
        if torrent and not torrent.status.isActive(pause = False):
            self.updateNetwork('tracker', [torrent.getTracker(), '', ''])
        # Fit scrollbars
        self.generalPage.FitInside()
        self.networkPage.FitInside()
        self.filesPage.FitInside()
        self.peersPage.FitInside()
        self.graphPage.FitInside()
                    
    def updateGeneral(self):
        self.generalPage.loadValues()

    def updateNetwork(self, section = None, *args, **kwargs):
        self.networkPage.loadValues(section, *args, **kwargs)

    def updatePeers(self, spew = None):
        self.peersPage.loadValues(spew)

    def updateFiles(self):
        self.filesPage.loadValues()

    def updateSettings(self):
        self.settingPage.loadValues()
        self.settingPage.FitInside()

    def updateGraph(self, uploadRate = None, downloadRate = None):
        self.graphPage.loadValues(uploadRate, downloadRate)
        
class NetworkPanel(BasePanel):
    def __init__(self, parent, title = None):
        def StaticText(self, id, text):
            t = wx.StaticText(self, id, text)
            font = t.GetFont()
            font.SetWeight(wx.BOLD)
            t.SetFont(font)
            return t
        
        BasePanel.__init__(self, parent, title)
        self.SetScrollRate(20,20)

        transferTitle = TitlePanel(self, _("Transfer"))
        self.sizer.Add(transferTitle, 0, wx.EXPAND, 0)
        self.sizer.Add((-1, 5))
        
        transferBox = wx.GridSizer(0, 6, 5, 5)

        transferBox.Add(StaticText(self, -1, _('Time Elapsed:')))              
        self.elapsed = wx.StaticText(self, -1)
        transferBox.Add(self.elapsed)
        transferBox.Add(StaticText(self, -1, _('Time Remaining:')))              
        self.remaining = wx.StaticText(self, -1)
        transferBox.Add(self.remaining)
        transferBox.Add(StaticText(self, -1, _('Connectable:')))              
        self.connectable = wx.StaticText(self, -1)
        transferBox.Add(self.connectable)
        transferBox.Add(StaticText(self, -1, _('Downloaded:')))
        self.downloaded = wx.StaticText(self, -1)
        transferBox.Add(self.downloaded)
        transferBox.Add(StaticText(self, -1, _('Download Speed:')))              
        self.downloadSpeed = wx.StaticText(self, -1)
        transferBox.Add(self.downloadSpeed)
        transferBox.Add(StaticText(self, -1, _('Progress:')))              
        self.progress = wx.StaticText(self, -1)
        transferBox.Add(self.progress)        
        transferBox.Add(StaticText(self, -1, _('Uploaded:')))              
        self.uploaded = wx.StaticText(self, -1)
        transferBox.Add(self.uploaded)
        transferBox.Add(StaticText(self, -1, _('Upload Speed:')))              
        self.uploadSpeed = wx.StaticText(self, -1)
        transferBox.Add(self.uploadSpeed)
        transferBox.Add(StaticText(self, -1, _('Share Ratio:')))              
        self.ratio = wx.StaticText(self, -1)
        transferBox.Add(self.ratio)
        transferBox.Add(StaticText(self, -1, _('Seeds:')))              
        self.seeds = wx.StaticText(self, -1)
        transferBox.Add(self.seeds)
        transferBox.Add(StaticText(self, -1, _('Peers:')))              
        self.peers = wx.StaticText(self, -1)
        transferBox.Add(self.peers)
        transferBox.Add(StaticText(self, -1, _('Copies:')))              
        self.copies = wx.StaticText(self, -1)
        transferBox.Add(self.copies)
        self.sizer.Add(transferBox, 0, wx.EXPAND|wx.LEFT, 8)

        self.sizer.Add((-1, 10))
        
        trackerTitle = TitlePanel(self, _("Tracker"))
        self.sizer.Add(trackerTitle, 0, wx.EXPAND, 0)
        self.sizer.Add((-1, 5))
        trackerBox = wx.FlexGridSizer(0, 2, 5, 5)
        trackerBox.Add(StaticText(self, -1, _('URL:')))              
        self.trackerURL = wx.StaticText(self, -1)
        trackerBox.Add(self.trackerURL)
        trackerBox.Add(StaticText(self, -1, _('Status:')))              
        self.trackerStatus = wx.StaticText(self, -1)
        trackerBox.Add(self.trackerStatus)
        trackerBox.Add(StaticText(self, -1, _('DHT:')))              
        self.DHTStatus = wx.StaticText(self, -1)
        trackerBox.Add(self.DHTStatus)
        self.sizer.Add(trackerBox, 0, wx.EXPAND|wx.LEFT, 8)
        
        self.sizer.Add((-1, 10))

        storageInfoTitle = TitlePanel(self, _("Storage"))
        self.sizer.Add(storageInfoTitle, 0, wx.EXPAND, 0)
        self.sizer.Add((-1, 5))
        storageBox = wx.FlexGridSizer(0, 2, 5, 5)        
        storageBox.Add(StaticText(self, -1, _('Completed:')))              
        self.storageCompleted = wx.StaticText(self, -1)
        storageBox.Add(self.storageCompleted)        
        storageBox.Add(StaticText(self, -1, _('Downloading:')))              
        self.storageDownloading = wx.StaticText(self, -1)
        storageBox.Add(self.storageDownloading)
        storageBox.Add(StaticText(self, -1, _('Redundant Data:')))              
        self.storageDiscarded = wx.StaticText(self, -1)
        storageBox.Add(self.storageDiscarded)
        self.sizer.Add(storageBox, 0, wx.EXPAND|wx.LEFT, 8)

        self.initTasks()
        
    def loadValues(self, section = 'transfer', args = [], kwargs = {}):
        """
        @param section - transfer, tracker or general.
        """
        if self.parent.getTorrent() is None:
            self.updateTransfer(True)
            self.updateTracker('','', '')
            self.updateStorage()
        elif section == 'tracker':
            self.updateTracker(*args, **kwargs)
        elif section == 'storage':
            self.updateStorage(*args, **kwargs)
        else:
            self.updateTransfer(*args, **kwargs)

            
    def updateTransfer(self, clear = False):
        if clear:
            self.progress.SetLabel('')
            self.remaining.SetLabel('')
            self.connectable.SetLabel('')
            self.ratio.SetLabel('')
            self.downloaded.SetLabel('')
            self.downloadSpeed.SetLabel('')
            self.uploaded.SetLabel('')
            self.uploadSpeed.SetLabel('')
            self.seeds.SetLabel('')
            self.peers.SetLabel('')
            self.copies.SetLabel('')
            self.elapsed.SetLabel('')
            return
                
        torrent = self.parent.getTorrent()
        
        self.progress.SetLabel(torrent.getColumnText(COL_PROGRESS, True))
        self.remaining.SetLabel(torrent.getColumnText(COL_ETA))
        self.ratio.SetLabel(torrent.getColumnText(COL_RATIO))
        self.downloaded.SetLabel(torrent.getColumnText(COL_DLSIZE))
        self.downloadSpeed.SetLabel(torrent.getColumnText(COL_DLSPEED))
        self.uploaded.SetLabel(torrent.getColumnText(COL_ULSIZE))
        self.uploadSpeed.SetLabel(torrent.getColumnText(COL_ULSPEED))

        if torrent.status.isActive(pause = False):
            if torrent.connection.engine.hadextern:
                self.connectable.SetLabel(_("Yes"))
            else:
                self.connectable.SetLabel(_("?"))
            self.seeds.SetLabel("%d / %s" % (torrent.connection.engine.numseeds, str(torrent.totalseeds)))
            self.peers.SetLabel("%d / %s" % (torrent.connection.engine.numpeers, str(torrent.totalpeers)))
            if torrent.connection.engine.numcopies:
                self.copies.SetLabel("%0.3f" % (torrent.connection.engine.numcopies))
            else:
                self.copies.SetLabel('0.000')           
            self.elapsed.SetLabel(torrent.connection.engine.elapsed)
        else:
            self.connectable.SetLabel('')
            self.seeds.SetLabel("0 / %s" % (str(torrent.totalseeds)))
            self.peers.SetLabel("0 / %s" % (str(torrent.totalpeers)))
            self.copies.SetLabel('0.000')
            self.elapsed.SetLabel('')
            
    def updateTracker(self, trackerURL = None, trackerStatus = None, dhtPeers = ''):
        # Tracker URL
        if trackerURL is not None and trackerURL != self.trackerURL.GetLabel():
            self.trackerURL.SetLabel(trackerURL)
        # Tracker status
        if trackerStatus != self.trackerStatus.GetLabel():  
            if trackerStatus is None:
                self.trackerStatus.SetLabel(_('connecting'))
            elif trackerStatus == "working":
                self.trackerStatus.SetLabel(_('working'))
            else:
                self.trackerStatus.SetLabel(trackerStatus)
        # DHT Peers
        if type(dhtPeers) != type(0):
            dhtLabel = ""
        elif dhtPeers >= 0:
            dhtLabel = _("%d peers") % dhtPeers
        else:
            dhtLabel = _("Disabled")
        if dhtLabel != self.DHTStatus.GetLabel():  
            self.DHTStatus.SetLabel(dhtLabel)        

    def updateStorage(self, statistics = None):
        if not statistics:
            self.storageCompleted.SetLabel('')
            self.storageDownloading.SetLabel('')
            self.storageDiscarded.SetLabel('')
            return
        
        self.storageCompleted.SetLabel(_('%d of %d pieces (%d just downloaded)') % (statistics.storage_numcomplete,
                                                                                    statistics.storage_totalpieces,
                                                                                    statistics.storage_justdownloaded))

        self.storageDiscarded.SetLabel(_('%s discarded, %d failed hash check (%s)') % (utility.size_format(statistics.discarded),
                                                                                       statistics.storage_numflunked,
                                                                                       utility.size_format(statistics.storage_sizeflunked)))
        if statistics.storage_numcomplete == statistics.storage_totalpieces:
            self.storageDownloading.SetLabel('')
        else:
            label = _('%d pieces (%d just started), %d partially received')
            if statistics.storage_isendgame:
                label += _(', endgame mode')
            self.storageDownloading.SetLabel(label % (statistics.storage_active,
                                                      statistics.storage_new,
                                                      statistics.storage_dirty))        
            
class GeneralPanel(BasePanel):
    def __init__(self, parent, title = None):
        BasePanel.__init__(self, parent, title)
        
        if wx.Platform == "__WXGTK__":
            self.sizer.Add((-1,10))
        else:
            self.sizer.Add(TitlePanel(self, _("General")), 0, wx.EXPAND, 0)

        self.list = GeneralInfoList(self)
        self.list.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
        self.sizer.Add(self.list, 1, wx.EXPAND, 0)
        
        self.initTasks()
        
        self.sizer.SetSizeHints(self.list)

    def OnSysColourChange(self, event):
        self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
        self.list.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
        event.Skip()
        
    def loadValues(self):
        self.list.loadValues(self.parent.getTorrent())
        
class PeersPanel(BasePanel):
    def __init__(self, parent, title = None):
        BasePanel.__init__(self, parent, title)
        self.spewList = PeersList(self)
        if wx.Platform == "__WXMAC__":
            self.spewList.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
        self.sizer.Add(self.spewList, 1, wx.EXPAND, 0)
        self.initTasks()
        
        self.sizer.SetSizeHints(self.spewList)
        
    def loadValues(self, spew = None):
        if spew is not None:
            self.spewList.updateSpew(spew)
        else:
            self.spewList.clearSpew()
            
class FilesPanel(BasePanel):
    def __init__(self, parent, title = None):
        BasePanel.__init__(self, parent, title)
        self.fileList = FileInfoList(self)
        if wx.Platform == "__WXMAC__":
            self.fileList.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
        
        self.il = wx.ImageList(16, 16)
        self.images = {}
        self.cache = {}
        self.images['folder'] = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_TOOLBAR, (16, 16)))
        self.images['folder_open'] = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, (16, 16)))
        self.images['file'] = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_TOOLBAR, (16, 16)))
        self.fileList.SetImageList(self.il)

        self.sizer.Add(self.fileList, 1, wx.EXPAND, 0)
        self.initTasks()
        
        self.sizer.SetSizeHints(self.fileList)
        
    def loadValues(self):
        self.fileList.DeleteAllItems()
        torrent = self.parent.getTorrent()
        if torrent is None:
            return
        
        self.filemap = {}
        info = torrent.info
        if torrent.files.isFile():
            filename = os.path.split(torrent.files.getProcDest(pathonly = False, checkexists = False))[1]
            root = self.fileList.AddRoot(filename)
            self.filemap[0] = root
            self.fileList.SetItemImage(root, self.getFiletypeImage(filename.split('.')[-1]),
                                       which = wx.TreeItemIcon_Normal)

        else:
            root = self.fileList.AddRoot(torrent.getTitle("dest"))
            self.fileList.SetItemImage(root, self.images['folder'], which = wx.TreeItemIcon_Normal)
            self.fileList.SetItemImage(root, self.images['folder_open'], which = wx.TreeItemIcon_Expanded)

            alreadypresent = {}
            filearray = []
            
            for fileindex in range(len(info['files'])):
                tempfile = info['files'][fileindex]
                patharray = tempfile['path']
                
                relativepath = u""
                addto = self.fileList.GetRootItem()
                # Add directories first
                if len(patharray) > 1:
                    for index in range(len(patharray) - 1):
                        part = patharray[index]
    
                        relativepath += "\\" + part
                        
                        if not relativepath in alreadypresent:
                            newitem = self.fileList.AppendItem(addto, part)
                            
                            self.fileList.SetItemImage(newitem, self.images['folder'], which = wx.TreeItemIcon_Normal)
                            self.fileList.SetItemImage(newitem, self.images['folder_open'], which = wx.TreeItemIcon_Expanded)
                            alreadypresent[relativepath] = newitem
                        
                        addto = alreadypresent[relativepath]
                
                filearray.append((patharray, addto))
                
            # Add files after adding directories
            for index in range(len(filearray)):
                patharray, addto = filearray[index]
                filename = patharray[-1]
                
                newitem = self.fileList.AppendItem(addto, filename)
                
                self.filemap[index] = newitem
                
                self.fileList.SetItemImage(newitem, self.getFiletypeImage(filename.split('.')[-1]),
                                           which = wx.TreeItemIcon_Normal)
        
        # Default to having the root expanded
        self.fileList.Expand(root)
        
        self.fileList.onUpdateColumns()

    def getFiletypeImage(self, filetype):
        if not filetype or wx.Platform != "__WXMSW__":
            return self.images['file']
        
        if not self.images.has_key(filetype):
            icon, iconfile, iconidx = getIcon(filetype)
            if icon and icon.Ok():
                if (iconfile, iconidx) in self.cache:
                    self.images[filetype] = self.cache[(iconfile, iconidx)]
                else:
                    self.images[filetype] = self.il.AddIcon(icon)
                    self.cache[(iconfile, iconidx)] = self.images[filetype]
                self.fileList.SetImageList(self.il)
            else:
                self.images[filetype] = self.images['file']

        return self.images[filetype]
    
class LocalSetting(BasePanel):
    """
    Allows for setting local limits on rates or changing the
    upload options for torrents on an individual basis.
    """
    def __init__(self, parent, title = None):
        BasePanel.__init__(self, parent, title)
        self.SetScrollRate(20,20)
        
        if wx.Platform == "__WXGTK__":
            self.sizer.Add((-1,10))
        else:
            self.sizer.Add(TitlePanel(self, _("Torrent Local Settings")), 0, wx.EXPAND, 0)

        self.settingSizer = wx.BoxSizer(wx.HORIZONTAL)
        
        # Bandwidth
        ###################
        ratesection = wx.StaticBoxSizer(wx.StaticBox(self, -1, _('Bandwidth limits')), wx.VERTICAL)
        # Max uploads 
        maxuploadsbox = wx.BoxSizer(wx.HORIZONTAL)
        maxuploadsbox.Add(wx.StaticText(self, -1, _('Maximum uploads:')), 0, wx.ALIGN_CENTER_VERTICAL)
        maxuploadsbox.Add((-1, -1), 1)
        self.maxupload = wx.SpinCtrl(self, size = wx.Size(60, -1))
        self.maxupload.SetRange(2, 100)
        maxuploadsbox.Add(self.maxupload, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        ratesection.Add(maxuploadsbox, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        # Upload limit
        maxoverall_up = wx.BoxSizer(wx.HORIZONTAL)
        maxoverall_up.Add(wx.StaticText(self, -1, _('Upload rate (KB/s):')), 0, wx.ALIGN_CENTER_VERTICAL)
        maxoverall_up.Add((-1, -1), 1)
        self.uploadrate = wx.SpinCtrl(self, size = wx.Size(60, -1))
        self.uploadrate.SetRange(0, 9999)
        maxoverall_up.Add(self.uploadrate, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        ratesection.Add(maxoverall_up, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        # Download limit
        maxdownoverall_down = wx.BoxSizer(wx.HORIZONTAL)
        maxdownoverall_down.Add(wx.StaticText(self, -1, _('Download rate (KB/s):')), 0, wx.ALIGN_CENTER_VERTICAL)
        maxdownoverall_down.Add((-1, -1), 1)
        self.downloadrate = wx.SpinCtrl(self, size = wx.Size(60, -1))
        self.downloadrate.SetRange(0, 9999)
        maxdownoverall_down.Add(self.downloadrate, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        ratesection.Add(maxdownoverall_down, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
        # Note
        ratesection.Add((-1,-1), 1, wx.ALIGN_RIGHT, 0)
        ratesection.Add(wx.StaticText(self, wx.ID_STATIC, _("0 = Global")), 0, wx.ALIGN_RIGHT, 0)
        self.settingSizer.Add(ratesection, 0, wx.EXPAND|wx.ALL, 3)

        # Seeding options
        ###################
        continuesection = wx.StaticBoxSizer(wx.StaticBox(self, -1, _('Queue')), wx.VERTICAL)
        # Time
        timesizer = wx.BoxSizer(wx.HORIZONTAL)
        timesizer.Add(wx.StaticText(self, -1, _('Seeding Time: ')), 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)       
        self.cbtime = DHMTimeCtrl(self)
        timesizer.Add(self.cbtime, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        timesizer.Add(self.cbtime.GetSpinButton(), 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 2)
        continuesection.Add(timesizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.LEFT, 5)
        # Ratio
        ratiosizer = wx.BoxSizer(wx.HORIZONTAL)
        ratiosizer.Add(wx.StaticText(self, -1, _('Seeding Ratio:')), 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)
        ratioval = ['0', '50', '60', '70', '75', '80', '90', '100', '125', '150', '175', '200', '300', '400', '500']
        self.cbratio = wx.ComboBox(self, -1, "", wx.Point(-1, -1), wx.Size(65, -1), ratioval, wx.CB_DROPDOWN|wx.CB_READONLY)
        ratiosizer.Add(self.cbratio, 1, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        ratiosizer.Add(wx.StaticText(self, -1, "%"), 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)
        continuesection.Add(ratiosizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.LEFT | wx.UP, 5)
        # Note
        continuesection.Add((-1,-1), 1, wx.ALIGN_RIGHT, 0)
        continuesection.Add(wx.StaticText(self, wx.ID_STATIC, _("0 = Ignore")), 0, wx.ALIGN_RIGHT, 0)
        continuesection.Add((-1,-1), 1, wx.ALIGN_RIGHT, 0)
        # Timeouts
        self.distimeouts = wx.CheckBox(self, -1, _("Disable timeouts"))
        continuesection.Add(self.distimeouts, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        
        self.settingSizer.Add(continuesection, 0, wx.EXPAND|wx.ALL, 3)
        
        # Announce List
        ###################
        announcesection = wx.StaticBoxSizer(wx.StaticBox(self, -1, _('Announce List')), wx.VERTICAL)
        self.annListCtl = wx.TextCtrl(self, -1, size = (-1, 75), style = wx.TE_MULTILINE|wx.HSCROLL|wx.TE_DONTWRAP)
        self.annListCtl.SetToolTipString(_('A list of announces separated by commas or whitespace'))
        announcesection.Add(self.annListCtl, 1, wx.EXPAND, 0)
        self.settingSizer.Add(announcesection, 1, wx.EXPAND|wx.ALL, 3)

        # Buttons
        ###################
        self.savebtn  = wx.Button(self, wx.ID_SAVE, _('Save'))
        self.revertbtn = wx.Button(self, wx.ID_REVERT_TO_SAVED, _('Revert to Saved'))
        self.defaultbtn = wx.Button(self, wx.ID_DEFAULT, _('Revert to Default'))

        buttonbox = wx.BoxSizer(wx.HORIZONTAL)
        buttonbox.Add(self.savebtn,  0, wx.EXPAND|wx.ALL, 5)
        buttonbox.Add(self.revertbtn, 0, wx.EXPAND|wx.ALL, 5)
        buttonbox.Add(self.defaultbtn, 0, wx.EXPAND|wx.ALL, 5)

        # Put it all together
        self.sizer.Add(self.settingSizer, 1, wx.EXPAND|wx.ALL, 5)
        self.sizer.Add(buttonbox, 0, wx.ALIGN_CENTER)

        # events
        self.Bind(wx.EVT_TEXT, self.onChanged)
        self.Bind(wx.EVT_CHECKBOX, self.onChanged)
        self.Bind(wx.EVT_BUTTON, self.onSave, self.savebtn)
        self.Bind(wx.EVT_BUTTON, self.revertToSaved, self.revertbtn)
        self.Bind(wx.EVT_BUTTON, self.revertToDefault, self.defaultbtn)
        
        self.initTasks()
        
    def onChanged(self, event):
        if self.IsEnabled():
            self.revertbtn.Enable()
            self.savebtn.Enable()
        event.Skip()

    def defaultChanged(self):
        torrents = self.parent.getTorrents()
        if not torrents:
            return

        if not self.savebtn.IsEnabled():
            if torrents[0].connection.getMaxUpload(localonly = True) == None:
                self.maxupload.SetValue(torrents[0].connection.getMaxUpload())
            if torrents[0].connection.getSeedOption('uploadtime', localonly = True) == None:
                cbtime = int(torrents[0].connection.getSeedOption('uploadtime'))
                self.cbtime.SetValue(cbtime)
            if torrents[0].connection.getSeedOption('uploadratio', localonly = True) == None:
                self.cbratio.SetValue(torrents[0].connection.getSeedOption('uploadratio'))
            self.distimeouts.SetValue(False)
            self.revertbtn.Disable()
            self.savebtn.Disable()

    def torrentsChanged(self):
        numtorrents = len(self.parent.getTorrents())
        if numtorrents == 0:
            self.Disable()
        elif numtorrents == 1:
            self.loadValues()
        else:
            self.loadAnnounceList()

    def loadValues(self):
        torrents = self.parent.getTorrents()
        self.annListCtl.Clear()
        
        if not torrents:
            self.Disable()
            return

        # Update settings
        self.Enable()
        self.maxupload.SetValue(torrents[0].connection.getMaxUpload())
        self.cbratio.SetValue(torrents[0].connection.getSeedOption('uploadratio'))

        cbtime = int(torrents[0].connection.getSeedOption('uploadtime'))
        self.cbtime.SetValue(cbtime)
        
        self.uploadrate.SetValue(torrents[0].connection.getLocalRate('up'))
        self.downloadrate.SetValue(torrents[0].connection.getLocalRate('down'))
        
        self.distimeouts.SetValue(not torrents[0].connection.timeout)
        
        # Update Trackers
        self.loadAnnounceList(torrents)
        
        self.revertbtn.Disable()
        self.savebtn.Disable()

    def loadAnnounceList(self, torrents = None):
        if torrents is None:
            torrents = self.parent.getTorrents()
        self.annListCtl.Clear()
        if len(torrents) == 1:
            self.annListCtl.Enable()
            text = ""
            for item in torrents[0].trackerlist:
                for tracker in item:
                    text += tracker + ' '
                text += '\n'
            self.annListCtl.AppendText(text)
        else:
            self.annListCtl.AppendText(_("Disabled"))
            self.annListCtl.Disable()
        
    def onSave(self, event = None):
        torrents = self.parent.getTorrents()
        if not torrents:
            return False
        
        upload_rate = int(self.uploadrate.GetValue())
        if upload_rate < 3 and upload_rate != 0:
            #display warning
            dlg = wx.MessageDialog(self, _('Upload rate must be at least 3 KB/s')  , _('Error'), wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        loc_info = {}

        # Update tracker list
        if len(torrents) == 1:
            loc_info['announces'] = self.getAnnounceList()

        loc_info['maxupload'] = self.maxupload.GetValue()      #maxupload
        loc_info['uploadrate'] = self.uploadrate.GetValue()     #maxuploadrate
        loc_info['downloadrate'] = self.downloadrate.GetValue()     #maxdownloadrate
        
        cbtime = self.cbtime.GetValue(asInt = True)
        if 0 != cbtime < 1800:
            cbtime = 1800
        loc_info['uploadtime']  = cbtime                        #uploadtime 
        loc_info['uploadratio'] = self.cbratio.GetValue()       #uploadratio

        loc_info['timeout'] = not self.distimeouts.GetValue()
        
        for torrent in torrents:
            torrent.connection.changeLocalInfo(loc_info)
        utility.queue.updateAndInvoke()
        
        self.revertbtn.Disable()
        self.savebtn.Disable()
        
        return True
    
    def getAnnounceList(self):
        text = self.annListCtl.GetValue()
        list = []
        for tier in text.split('\n'):
            sublist = []
            tier = tier.replace(',', ' ')
            for tracker in tier.split(' '):
                if tracker.strip() != '':
                    sublist += [tracker]
            if sublist:
                list.append(sublist)
        return list

    def revertToSaved(self, event = None):
        self.loadValues()

    def revertToDefault(self, event = None):
        self.maxupload.SetValue(utility.config.Read('maxupload', "int"))
        self.cbratio.SetValue(utility.config.Read('uploadratio'))        

        cbtime = utility.config.Read('uploadtime', "int")
        self.cbtime.SetValue(cbtime)
                
        self.uploadrate.SetValue(0)
        self.downloadrate.SetValue(0)

        # Update Trackers
        torrents = self.parent.getTorrents()
        if len(torrents) == 1:
            self.annListCtl.Clear()
            text = ""
            for item in torrents[0].originalTrackers:
                for tracker in item:
                    text += tracker + ' '
                text += '\n'
            self.annListCtl.AppendText(text)
        self.onSave()                

class GraphPanel(BasePanel):
    def __init__(self, parent, title = None):
        BasePanel.__init__(self, parent, title, style = wx.NO_FULL_REPAINT_ON_RESIZE)
        self.SetScrollRate(20, 20)
        
        # Scale
        self.x_scale = 300
        self.y_scale = 25
        
        # Graph
        self.graph = Graph(self, 15, _("%d minutes") % (self.x_scale*2/60), _("%d KB/s") % (self.y_scale), size=(100,100))
        
        # Records
        self.total_urate = GraphRecord(wx.GREEN, self.x_scale, self.y_scale, 1)
        self.total_drate = GraphRecord(wx.RED, self.x_scale, self.y_scale, 1)
        self.graph.AddRecord(self.total_urate)
        self.graph.AddRecord(self.total_drate)

        # Background
        self.SetBackgroundColour(wx.Colour(255,255,255))

        # Boxes        
        legsizer = wx.BoxSizer(wx.HORIZONTAL)
        tdnratebox =  wx.Panel(self, -1, size=(20,10), style = wx.SIMPLE_BORDER)
        tdnratebox.SetBackgroundColour(wx.RED)
        tupratebox =  wx.Panel(self, -1, size=(20,10), style = wx.SIMPLE_BORDER)
        tupratebox.SetBackgroundColour(wx.GREEN)
        legsizer.Add(tdnratebox, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5)
        legsizer.Add(wx.StaticText(self, -1, _("Total download rate")), 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        legsizer.Add(tupratebox, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5)
        legsizer.Add(wx.StaticText(self, -1, _("Total upload rate")), 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        
        self.sizer.Add(self.graph, 1, wx.EXPAND|wx.FIXED_MINSIZE)
        self.sizer.Add(legsizer, 0, wx.EXPAND|wx.FIXED_MINSIZE|wx.ALL, 4)

        self.initTasks()
        self.Layout()
                        
    def updateGraph(self):
        # First take the maximum out of the bandwidth settings
        max_drate = utility.config.Read('maxdownloadrate', "int")
        if utility.torrents["downloading"]:
            max_urate = utility.config.Read('maxuploadrate', "int")
        else:
            max_urate = utility.config.Read('maxseeduploadrate', "int")
        maxy = max(max_drate, max_urate, 1)
        # Then check for the maximum shown bandwidth 
        maxy = max(self.graph.GetMaxValue(), maxy)
        if self.y_scale != maxy:
            self.y_scale = maxy
            self.graph.yaxis_text[0] = _("%0.1f KB/s") % maxy
            self.graph.SetYMax(maxy, True)
        if utility.frame.GUIupdate:
            self.graph.UpdateGraph()
                    
    def AppendUploadRate(self, value):
        if value == None:
            value = 0            
        self.total_urate.AddValue(value)
    
    def AppendDownloadRate(self, value):
        if value == None:
            value = 0
        self.total_drate.AddValue(value)

    def loadValues(self, uploadRate = None, downloadRate = None):
        if uploadRate is not None or downloadRate is not None:
            self.AppendUploadRate(uploadRate)
            self.AppendDownloadRate(downloadRate)
            self.updateGraph()